﻿using UnityEngine;
using System.Collections;
using System;
using System.Threading;

[RequireComponent(typeof(AudioSource))]

public class Brainner : MonoBehaviour
{
    public static long ticks;
    public static float timed;
	public static int currFpsBuildCount;
	public static float MAX_AUDIO_VALUE;

    public GameObject nodePre;
//    public Material materialDef;
//    public Material materialLig;
//    public Material materialBlack;
    private AudioClip audioClip;
    private int SamplingRate = 8000;
    private int audioLen = 3;
    private int lastPos;

	public BrainCore nodeJ; //金
	public BrainCore nodeM; //木
	public BrainCore nodeS; //水
	public BrainCore nodeH; //火
	public BrainCore nodeT; //土

	 BrainCore nodeHear;//听
	 BrainCore nodeHear1;//听
	 BrainCore nodeHear2;//听
	 BrainCore nodeHear3;//听
	 BrainCore nodeHear4;//听
	 BrainCore nodeHear5;//听
	 BrainCore nodeHear6;//听
	 BrainCore nodeHear7;//听
	 BrainCore nodeSay;//说
	 BrainCore nodeSay1;//说
	 BrainCore nodeSay2;//说
	 BrainCore nodeSay3;//说
	 BrainCore nodeSay4;//说
	 BrainCore nodeSay5;//说
	 BrainCore nodeSay6;//说
	 BrainCore nodeSay7;//说

    private float audioWaitTime;
    private float[] data;
    private int hn;

    private AudioClip audioOut;
    private AudioSource audioSrc;
    private float[] audioData;
    private int k,ak;

	public float thresholds;

    // Use this for initialization
    void Start()
    {
        ticks = DateTime.Now.Ticks;
		
		MAX_AUDIO_VALUE = (float)((1 << 7) + (1 << 6) + (1 << 5) + (1 << 4) + (1 << 3) + (1 << 2) + (1 << 1) + 1);

		nodeHear = addNode("NodeHear", new Vector3 (UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5)),BrainCore.ATTR_S);
		nodeHear1 = addNode("NodeHear (1)", new Vector3 (UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5)),BrainCore.ATTR_S);
		nodeHear2 = addNode("NodeHear (2)", new Vector3 (UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5)),BrainCore.ATTR_S);
		nodeHear3 = addNode("NodeHear (3)", new Vector3 (UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5)),BrainCore.ATTR_S);
		nodeHear4 = addNode("NodeHear (4)", new Vector3 (UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5)),BrainCore.ATTR_S);
		nodeHear5 = addNode("NodeHear (5)", new Vector3 (UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5)),BrainCore.ATTR_S);
		nodeHear6 = addNode("NodeHear (6)", new Vector3 (UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5)),BrainCore.ATTR_S);
		nodeHear7 = addNode("NodeHear (7)", new Vector3 (UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5)),BrainCore.ATTR_S);

		nodeSay = addNode("NodeSay", new Vector3 (UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5)),BrainCore.ATTR_H);
		nodeSay1 = addNode("NodeSay (1)", new Vector3 (UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5)),BrainCore.ATTR_H);
		nodeSay2 = addNode("NodeSay (2)", new Vector3 (UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5)),BrainCore.ATTR_H);
		nodeSay3 = addNode("NodeSay (3)", new Vector3 (UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5)),BrainCore.ATTR_H);
		nodeSay4 = addNode("NodeSay (4)", new Vector3 (UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5)),BrainCore.ATTR_H);
		nodeSay5 = addNode("NodeSay (5)", new Vector3 (UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5)),BrainCore.ATTR_H);
		nodeSay6 = addNode("NodeSay (6)", new Vector3 (UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5)),BrainCore.ATTR_H);
		nodeSay7 = addNode("NodeSay (7)", new Vector3 (UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5),UnityEngine.Random.Range(-5f,5)),BrainCore.ATTR_H);

        audioOut = AudioClip.Create("sayer", 3 * SamplingRate, 1, SamplingRate, false);

        audioData = new float[3 * SamplingRate];
        //int n = audioData.Length / 2;
        //for (int i = 0; i < audioData.Length; i++)
        //{
        //    float rate = (1f * (i < n ? i : 2 * n - i) / n);
        //    audioData[i] = UnityEngine.Random.Range(-1 * rate, 1 * rate);
        //}
        //audioOut.SetData(audioData, 0);
        audioSrc = GetComponent<AudioSource>();
        audioSrc.rolloffMode = AudioRolloffMode.Linear;
    }

    void Awake()
    {
		if (audioClip == null) {
			audioClip = Microphone.Start (null, true, audioLen, SamplingRate);
		}
    }


    // Update is called once per frame
    void Update()
	{
		ticks = DateTime.Now.Ticks;
		if (timed == 0) {
			timed = Time.deltaTime;
		} else {
			timed = (Time.deltaTime + timed) / 2;
		}

		float deltime = Time.deltaTime;
		if (deltime > 0.5f && BrainCore.MAX_UPDATE_BUILD_NUM>1) {
			BrainCore.MAX_UPDATE_BUILD_NUM = Math.Max(1,(int)(BrainCore.MAX_UPDATE_BUILD_NUM*0.75f));
			Debug.Log ("BrainCore.MAX_UPDATE_BUILD_NUM "+BrainCore.MAX_UPDATE_BUILD_NUM);
		}

		thresholds *= 0.5f;

//		nodeT.addValue (1f);
//		nodeJ.addValue (1f);
//		nodeS.addValue (1f);
//		nodeM.addValue (1f);
//		nodeH.addValue (1f);

		// 运行五行纽带
		float vj = nodeJ.value + nodeJ.threshold;
		if (vj > 0) {
			//Debug.Log ("vj: "+vj);
			nodeS.addValue (vj);
			nodeM.addValue (-vj);
		}
		float vm = nodeM.value + nodeM.threshold;
		if (vm > 0) {
			//Debug.Log ("vm: "+vm);
			nodeH.addValue (vm);
			nodeT.addValue (-vm);
		}
		float vs = nodeS.value + nodeS.threshold;
		if (vs > 0) {
			//Debug.Log ("vs: "+vs);
			nodeM.addValue (vs);
			nodeH.addValue (-vs);
		}
		float vh = nodeH.value + nodeH.threshold;
		if (vh > 0) {
			//Debug.Log ("vh: "+vh);
			nodeT.addValue (vh);
			nodeJ.addValue (-vh);
		}
		float vt = nodeT.value + nodeT.threshold;
		if (vt > 0) {
			//Debug.Log ("vt: "+vt);
			nodeJ.addValue (vt);
			nodeS.addValue (-vt);
		}

		// 向世界发声音
		float vol = 0;
		int j = (int)(SamplingRate * Time.deltaTime);

		vol += nodeSay.thresholed?(float)(1<<7):0;
		vol += nodeSay1.thresholed?(float)(1<<6):0;
		vol += nodeSay2.thresholed?(float)(1<<5):0;
		vol += nodeSay3.thresholed?(float)(1<<4):0;
		vol += nodeSay4.thresholed?(float)(1<<3):0;
		vol += nodeSay5.thresholed?(float)(1<<2):0;
		vol += nodeSay6.thresholed?(float)(1<<1):0;
		vol += nodeSay7.thresholed?1f:0;

		if (vol != 0) {
			vol %= MAX_AUDIO_VALUE;
			ak += j;
			//Debug.Log ("audio-vol: ("+(nodeSay.thresholed?"1":"0")+(nodeSay1.thresholed?"1":"0")+(nodeSay2.thresholed?"1":"0")+(nodeSay3.thresholed?"1":"0")+(nodeSay4.thresholed?"1":"0")+(nodeSay5.thresholed?"1":"0")+(nodeSay6.thresholed?"1":"0")+(nodeSay7.thresholed?"1":"0")+") "+ vol+"  maxv="+maxv);

			int n = Math.Min (j, SamplingRate) / 4;
			for (int i = 0; i < n && k + (2 * i + 1) < audioData.Length; i++) {
				float rate = 1f * i / n;
				audioData [2 * i + k] = (vol * rate) / MAX_AUDIO_VALUE;
				audioData [2 * i + 1 + k] = -(vol * rate) / MAX_AUDIO_VALUE;
				int li = 4 * n - (2 * i) - 1;
				if (k + li < audioData.Length) {
					audioData [k + li] = audioData [2 * i + k];
					audioData [k + li - 1] = audioData [2 * i + 1 + k];
				}
			}

			//		int n = Math.Min(j,SamplingRate) / 2;
			//        for (int i = 0; i < n && k + i < audioData.Length; i++)
			//        {
			//            float rate = 1f * UnityEngine.Random.Range(i + 1, n) / n;
			//            audioData[k + i] = (vol * rate * rate) / 128f;
			//            if (k + n + i < audioData.Length)
			//            {
			//                rate = (1f - rate);
			//                audioData[k + n + i] = (vol * rate * rate) / 128f;
			//            }
			//        }


		
		}

		k += j;
        
		if (k > audioData.Length) {
			audioSrc.Stop ();
			//Debug.Log ("audio-say: +" + j + ", len:" + audioData.Length);
			if (ak > 0) {
				Debug.Log ("audio-out:" + (1f*ak/SamplingRate) + ", node-count:" + BrainCore.count);

				audioOut.SetData (audioData, 0);
				audioSrc.clip = audioOut;
				audioSrc.Play ();
			}
			k = 0;
			ak = 0;
		}

		// 听世界的声音
		if (data != null && hn < data.Length) {
			float value = byte.MaxValue * data [hn];
//			if (value != 0) {
//				Debug.Log ("listen " + value);
//			}
			if (value > 0) {
				nodeHear.addValue (value);
				nodeHear1.addValue (value);
				nodeHear2.addValue (value);
				nodeHear3.addValue (value);
			}
			if (value < 0) {
				value *= -1f;
				nodeHear4.addValue (value);
				nodeHear5.addValue (value);
				nodeHear6.addValue (value);
				nodeHear7.addValue (value);
			}
//			if (hn + 3 < data.Length) {
//				float x = 6 * data [hn + 1];
//				float y = 6 * data [hn + 2];
//				float z = 6 * data [hn + 3];
//				if (x != 0 && y != 0 && z != 0) {
//					Vector3 space = new Vector3 (x, y, z);
//					GameObject node = (GameObject)Instantiate (Brainner.NodePre, nodeT.transform.position + space, nodeT.transform.rotation);
//					node.transform.parent = nodeT.transform.parent;
//					node.GetComponent<MeshRenderer> ().material.color = new Color (0, 0, 0.5f, 0.5f);
//				}
//			}
			hn += j;
		}

		currFpsBuildCount = 0;


		// 录制麦克风
		float audioLength;//录音的长度，单位为秒，ui上可能需要显示
		if (Microphone.IsRecording (null)) {
			//录音小于10秒
			lastPos = Microphone.GetPosition (null);
			audioLength = 1f * lastPos / SamplingRate;//录音时长
			audioWaitTime += Time.deltaTime;
		} else {
			audioLength = 0;
		}
		if (audioLength < 1 || audioWaitTime < audioLen) {
			return;//录音小于1秒就不处理了  
		}
		audioWaitTime = 0;
		data = new float[lastPos];
		audioClip.GetData (data, 0);
		hn = 0;

		//Debug.Log ("audio-in=" + audioLength + ", node-count:" + BrainCore.count);

	}

	public BrainCore addNode(string objName, Vector3 space, sbyte attr){
		Transform centerNodeTran = transform;
		switch(attr){
		case BrainCore.ATTR_H:
			centerNodeTran = nodeH.gameObject.transform;
			break;
		case BrainCore.ATTR_T:
			centerNodeTran = nodeT.gameObject.transform;
			break;
		case BrainCore.ATTR_J:
			centerNodeTran = nodeJ.gameObject.transform;
			break;
		case BrainCore.ATTR_S:
			centerNodeTran = nodeS.gameObject.transform;
			break;
		case BrainCore.ATTR_M:
			centerNodeTran = nodeM.gameObject.transform;
			break;
		}
		GameObject node = (GameObject)Instantiate (nodePre, centerNodeTran.position + space, centerNodeTran.rotation);
		node.name = objName;
		node.transform.parent = transform;
		BrainCore bcore = node.GetComponent<BrainCore> ();
		bcore.attr = attr;
		switch(attr){
		case BrainCore.ATTR_H:
			bcore.GetComponent<MeshRenderer> ().material.color = new Color (1f, 1f, 0, 0.5f);
			break;
		case BrainCore.ATTR_T:
			bcore.GetComponent<MeshRenderer> ().material.color = new Color (1f, 0.25f, 0, 0.5f);
			break;
		case BrainCore.ATTR_J:
			bcore.GetComponent<MeshRenderer> ().material.color = new Color (0.8f, 0.8f, 0.8f, 0.5f);
			break;
		case BrainCore.ATTR_S:
			bcore.GetComponent<MeshRenderer> ().material.color = new Color (0f, 0.75f, 1f, 0.5f);
			break;
		case BrainCore.ATTR_M:
			bcore.GetComponent<MeshRenderer> ().material.color = new Color (0f, 0.5f, 0f, 0.5f);
			break;
		}
		return bcore;
	}

	public void changeThreshold(float value){
		thresholds += value;
	}

}